/**
 * Apache License Version 2.0, January 2004 http://www.apache.org/licenses/
 *
 * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 *
 * 1. Definitions.
 *
 * "License" shall mean the terms and conditions for use, reproduction, and distribution as defined
 * by Sections 1 through 9 of this document.
 *
 * "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is
 * granting the License.
 *
 * "Legal Entity" shall mean the union of the acting entity and all other entities that control, are
 * controlled by, or are under common control with that entity. For the purposes of this definition,
 * "control" means (i) the power, direct or indirect, to cause the direction or management of such
 * entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
 * outstanding shares, or (iii) beneficial ownership of such entity.
 *
 * "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this
 * License.
 *
 * "Source" form shall mean the preferred form for making modifications, including but not limited
 * to software source code, documentation source, and configuration files.
 *
 * "Object" form shall mean any form resulting from mechanical transformation or translation of a
 * Source form, including but not limited to compiled object code, generated documentation, and
 * conversions to other media types.
 *
 * "Work" shall mean the work of authorship, whether in Source or Object form, made available under
 * the License, as indicated by a copyright notice that is included in or attached to the work (an
 * example is provided in the Appendix below).
 *
 * "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or
 * derived from) the Work and for which the editorial revisions, annotations, elaborations, or other
 * modifications represent, as a whole, an original work of authorship. For the purposes of this
 * License, Derivative Works shall not include works that remain separable from, or merely link (or
 * bind by name) to the interfaces of, the Work and Derivative Works thereof.
 *
 * "Contribution" shall mean any work of authorship, including the original version of the Work and
 * any modifications or additions to that Work or Derivative Works thereof, that is intentionally
 * submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or
 * Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this
 * definition, "submitted" means any form of electronic, verbal, or written communication sent to
 * the Licensor or its representatives, including but not limited to communication on electronic
 * mailing lists, source code control systems, and issue tracking systems that are managed by, or on
 * behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding
 * communication that is conspicuously marked or otherwise designated in writing by the copyright
 * owner as "Not a Contribution."
 *
 * "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a
 * Contribution has been received by Licensor and subsequently incorporated within the Work.
 *
 * 2. Grant of Copyright License. Subject to the terms and conditions of this License, each
 * Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
 * irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display,
 * publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or
 * Object form.
 *
 * 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor
 * hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 * (except as stated in this section) patent license to make, have made, use, offer to sell, sell,
 * import, and otherwise transfer the Work, where such license applies only to those patent claims
 * licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or
 * by combination of their Contribution(s) with the Work to which such Contribution(s) was
 * submitted. If You institute patent litigation against any entity (including a cross-claim or
 * counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work
 * constitutes direct or contributory patent infringement, then any patent licenses granted to You
 * under this License for that Work shall terminate as of the date such litigation is filed.
 *
 * 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works
 * thereof in any medium, with or without modifications, and in Source or Object form, provided that
 * You meet the following conditions:
 *
 * (a) You must give any other recipients of the Work or Derivative Works a copy of this License;
 * and
 *
 * (b) You must cause any modified files to carry prominent notices stating that You changed the
 * files; and
 *
 * (c) You must retain, in the Source form of any Derivative Works that You distribute, all
 * copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding
 * those notices that do not pertain to any part of the Derivative Works; and
 *
 * (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative
 * Works that You distribute must include a readable copy of the attribution notices contained
 * within such NOTICE file, excluding those notices that do not pertain to any part of the
 * Derivative Works, in at least one of the following places: within a NOTICE text file distributed
 * as part of the Derivative Works; within the Source form or documentation, if provided along with
 * the Derivative Works; or, within a display generated by the Derivative Works, if and wherever
 * such third-party notices normally appear. The contents of the NOTICE file are for informational
 * purposes only and do not modify the License. You may add Your own attribution notices within
 * Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the
 * Work, provided that such additional attribution notices cannot be construed as modifying the
 * License.
 *
 * You may add Your own copyright statement to Your modifications and may provide additional or
 * different license terms and conditions for use, reproduction, or distribution of Your
 * modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and
 * distribution of the Work otherwise complies with the conditions stated in this License.
 *
 * 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution
 * intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms
 * and conditions of this License, without any additional terms or conditions. Notwithstanding the
 * above, nothing herein shall supersede or modify the terms of any separate license agreement you
 * may have executed with Licensor regarding such Contributions.
 *
 * 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service
 * marks, or product names of the Licensor, except as required for reasonable and customary use in
 * describing the origin of the Work and reproducing the content of the NOTICE file.
 *
 * 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor
 * provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation,
 * any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 * PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or
 * redistributing the Work and assume any risks associated with Your exercise of permissions under
 * this License.
 *
 * 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including
 * negligence), contract, or otherwise, unless required by applicable law (such as deliberate and
 * grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for
 * damages, including any direct, indirect, special, incidental, or consequential damages of any
 * character arising as a result of this License or out of the use or inability to use the Work
 * (including but not limited to damages for loss of goodwill, work stoppage, computer failure or
 * malfunction, or any and all other commercial damages or losses), even if such Contributor has
 * been advised of the possibility of such damages.
 *
 * 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works
 * thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty,
 * indemnity, or other liability obligations and/or rights consistent with this License. However, in
 * accepting such obligations, You may act only on Your own behalf and on Your sole responsibility,
 * not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each
 * Contributor harmless for any liability incurred by, or claims asserted against, such Contributor
 * by reason of your accepting any such warranty or additional liability.
 *
 * END OF TERMS AND CONDITIONS
 *
 * APPENDIX: How to apply the Apache License to your work.
 *
 * To apply the Apache License to your work, attach the following boilerplate notice, with the
 * fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include
 * the brackets!)  The text should be enclosed in the appropriate comment syntax for the file
 * format. We also recommend that a file or class name and description of purpose be included on the
 * same "printed page" as the copyright notice for easier identification within third-party
 * archives.
 *
 * Copyright 2016 Alibaba Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.taobao.weex.ui.component;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.text.Layout;
import android.util.Log;
import android.view.ViewGroup;

import com.taobao.weex.WXEnvironment;
import com.taobao.weex.WXSDKInstance;
import com.taobao.weex.annotation.Component;
import com.taobao.weex.common.Constants;
import com.taobao.weex.dom.WXAttr;
import com.taobao.weex.dom.WXDomObject;
import com.taobao.weex.dom.WXStyle;
import com.taobao.weex.ui.ComponentCreator;
import com.taobao.weex.ui.view.WXTextView;
import com.taobao.weex.utils.FontDO;
import com.taobao.weex.utils.TypefaceUtil;
import com.taobao.weex.utils.WXLogUtils;

import java.lang.reflect.InvocationTargetException;

/**
 * Text component
 */
@Component(lazyload = false)
public class WXText extends WXComponent<WXTextView> {

    /**
     * The default text size
     **/
    public static final int sDEFAULT_SIZE = 32;
    private BroadcastReceiver mTypefaceObserver;
    private String mFontFamily;
    private DefaultBroadcastReceiver mReceiver;
    private Layout mCurrentLayout;
    private String mCurrentFontSize = "NORM";
    private String mChangeFontSize;
    private float mCurrentEnlarge;
    private float mCurrentScale = 1;


    public static class Creator implements ComponentCreator {

        public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer
                parent) throws IllegalAccessException, InvocationTargetException,
                InstantiationException {
            return new WXText(instance, node, parent);
        }
    }

    @Deprecated
    public WXText(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String
            instanceId, boolean isLazy) {
        this(instance, dom, parent);
    }

    public WXText(WXSDKInstance instance, WXDomObject node,
                  WXVContainer parent) {
        super(instance, node, parent);
        registerBroadCast();
        initFontSize();
        registerIconFont();
    }

    /**
     * 监听iconfont通知
     */
    private void registerIconFont() {
        WXStyle styles = getDomObject().getStyles();
        Object fontFamily = styles.get(Constants.Name.FONT_FAMILY);
        if (fontFamily != null) {
            IntentFilter filter = new IntentFilter();
            filter.addAction("com.benmu.inconfont.update");
            LocalBroadcastManager.getInstance(getContext()).registerReceiver(mReceiver, filter);
        }
    }

    /**
     * 自定义方法start
     **/
    private void initFontSize() {
        SharedPreferences sp = getContext().getSharedPreferences("JYT_NATIVE_SP", Context
                .MODE_PRIVATE);
        mChangeFontSize = sp.getString("SP_FONTSIZE", null);
    }

    private void registerBroadCast() {
        mReceiver = new DefaultBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.benmu.jyt.ACTION_GOBALFONTSIZE_CHANGE");
        LocalBroadcastManager.getInstance(getContext()).registerReceiver(mReceiver, filter);
    }

    private void updateFontSize() {

        if (getDomObject() != null && getDomObject().getStyles().get(Constants.Name.FONT_SIZE) ==
                null) {
            WXStyle s = getDomObject().getStyles();
            s.put(Constants.Name.FONT_SIZE, 30);
            updateStyle(s);
            return;
        }

        if (mChangeFontSize == null) {
            return;
        }

        WXStyle styles = null;
        WXAttr attrs = null;
        if (getDomObject() != null) {
            styles = getDomObject().getStyles();
            attrs = getDomObject().getAttrs();
            if ((styles != null && "iconfont".equals(styles.get("fontFamily"))) || (attrs != null
                    && attrs.get("changeFont") != null && !Boolean.valueOf((String) attrs.get
                    ("changeFont")))) {
                return;
            }
        }

        float scale = 0;
        //获取fontScale字段
        if (attrs != null && attrs.get("fontScale") != null) {
            float fontScale = Float.valueOf((String) attrs.get("fontScale"));
            mCurrentScale = fontScale / mCurrentScale;
        }
        if (mChangeFontSize.equals(mCurrentFontSize) && mCurrentScale == 1) {
            return;
        }
        //获取scale字段 在标准字体下不产生变化
        if (attrs != null && attrs.get("scale") != null && !(scale > 0)) {
            scale = Float.valueOf((String) attrs.get("scale"));
            float change = getFixedEnlarge(mChangeFontSize, scale);
            float current = getFixedEnlarge(mCurrentFontSize, scale);
            scale = change / current;
        }
        //根据全局字体配置设置字体大小
        if (!(scale > 0)) {
            float current = getEnlarge(mCurrentFontSize);
            float change = getEnlarge(mChangeFontSize);
            scale = change / current * mCurrentScale;
        }
        if (getDomObject() != null && getDomObject().getStyles() != null) {
            WXStyle wxStyle = getDomObject().getStyles();
            Object object = wxStyle.get("fontSize");
            if (object instanceof Integer) {
                int fontSize = (int) object;
                int changeFontSize = Math.round(fontSize * (scale));
                wxStyle.put("fontSize", changeFontSize);

            }
            //设置lineHeight
            Object lineHeight = wxStyle.get("lineHeight");
            if (lineHeight instanceof Integer) {
                int target = (int) lineHeight;
                wxStyle.put("lineHeight", Math.round(target * scale));
            }


            updateStyle(wxStyle);

        }
        mCurrentFontSize = mChangeFontSize;

    }

    /**
     * 自定义方法end
     **/


    @Override
    protected WXTextView initComponentHostView(@NonNull Context context) {
        WXTextView textView = new WXTextView(context);
        textView.holdComponent(this);
        return textView;
    }

    @Override
    public void updateExtra(Object extra) {
        if (extra instanceof Layout &&
                getHostView() != null && !extra.equals(getHostView().getTextLayout())) {
            final Layout layout = (Layout) extra;
            getHostView().setTextLayout(layout);
            getHostView().invalidate();
        }

        updateFontSize();
    }

    @Override
    public void refreshData(WXComponent component) {
        super.refreshData(component);
        if (component instanceof WXText) {
            updateExtra(component.getDomObject().getExtra());
        }
    }

    @Override
    protected boolean setProperty(String key, Object param) {
        switch (key) {
            case Constants.Name.LINES:
            case Constants.Name.FONT_SIZE:
            case Constants.Name.FONT_WEIGHT:
            case Constants.Name.FONT_STYLE:
            case Constants.Name.COLOR:
            case Constants.Name.TEXT_DECORATION:
            case Constants.Name.TEXT_ALIGN:
            case Constants.Name.TEXT_OVERFLOW:
            case Constants.Name.LINE_HEIGHT:
            case Constants.Name.VALUE:
                return true;
            case Constants.Name.FONT_FAMILY:
                if (param != null) {
                    // registerTypefaceObserver(param.toString());
                }
                return true;

            default:
                return super.setProperty(key, param);
        }
    }


    private void registerTypefaceObserver(String desiredFontFamily) {
        if (WXEnvironment.getApplication() == null) {
            WXLogUtils.w("WXText", "ApplicationContent is null on register typeface observer");
            return;
        }
        mFontFamily = desiredFontFamily;
        if (mTypefaceObserver != null) {
            return;
        }

        mTypefaceObserver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String fontFamily = intent.getStringExtra("fontFamily");
                if (!mFontFamily.equals(fontFamily)) {
                    return;
                }

                FontDO fontDO = TypefaceUtil.getFontDO(fontFamily);
                if (fontDO != null && fontDO.getTypeface() != null && getHostView() != null) {
                    WXTextView hostView = getHostView();
                    Layout layout = hostView.getTextLayout();
                    if (layout != null) {
                        layout.getPaint().setTypeface(fontDO.getTypeface());
                        WXLogUtils.d("WXText", "Apply font family " + fontFamily + " to paint");
                    } else {
                        WXLogUtils.w("WXText", "Layout not created");
                    }
                    hostView.invalidate();
                }
                WXLogUtils.d("WXText", "Font family " + fontFamily + " is available");
            }
        };

        LocalBroadcastManager.getInstance(WXEnvironment.getApplication()).registerReceiver(mTypefaceObserver, new IntentFilter(TypefaceUtil.ACTION_TYPE_FACE_AVAILABLE));
    }

    /**
     * Flush view no matter what height and width the {@link WXDomObject} specifies.
     *
     * @param extra must be a {@link Layout} object, otherwise, nothing will happen.
     */
    private void flushView(Object extra) {
        if (extra instanceof Layout &&
                getHostView() != null && !extra.equals(getHostView().getTextLayout())) {
            final Layout layout = (Layout) extra;
            /**The following if block change the height of the width of the textView.
             * other part of the code is the same to updateExtra
             */
            ViewGroup.LayoutParams layoutParams = getHostView().getLayoutParams();
            if (layoutParams != null) {
                layoutParams.height = layout.getHeight();
                layoutParams.width = layout.getWidth();
                getHostView().setLayoutParams(layoutParams);
            }
            getHostView().setTextLayout(layout);
            getHostView().invalidate();
        }
    }

    @Override
    protected Object convertEmptyProperty(String propName, Object originalValue) {
        switch (propName) {
            case Constants.Name.FONT_SIZE:
                return WXText.sDEFAULT_SIZE;
            case Constants.Name.COLOR:
                return "black";
        }
        return super.convertEmptyProperty(propName, originalValue);
    }

    /**
     * 自定义方法start
     **/

    private float getEnlarge(String fontsize) {
        if ("NORM".equals(fontsize)) {
            return 1;
        } else if ("BIG".equals(fontsize)) {
            return 1.15f;
        } else if ("EXTRALARGE".equals(fontsize)) {
            return 1.3f;
        } else {
            throw new RuntimeException("未知的字体大小" + fontsize);
        }
    }

    private float getFixedEnlarge(String fontsize, float scale) {
        if ("NORM".equals(fontsize)) {
            return 1;
        } else if ("BIG".equals(fontsize)) {
            return scale;
        } else if ("EXTRALARGE".equals(fontsize)) {
            return scale;
        } else {
            throw new RuntimeException("未知的字体大小" + fontsize);
        }
    }

    public class DefaultBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("com.benmu.inconfont.update")) {
                updateStyle(getDomObject().getStyles());
            } else {
                String size = intent.getStringExtra("currentFontSize");
                if (size == null) {
                    return;
                }
                mChangeFontSize = size;
                updateFontSize();
            }

        }
    }


    @Override
    public void onActivityDestroy() {
        super.onActivityDestroy();
        if (mReceiver != null) {
            LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mReceiver);
        }
    }
}
